package main

import (
	"database/sql"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"

	"test.com/fusion"
	"test.com/worlddb"
)

type LootSetPrototype struct {
	LsInfo     *worlddb.LootSet        `json:"lsInfo"`
	LsgIndexes []*worlddb.LootSetGroup `json:"lsgIndexes"`
	LootSetGroupPrototype
}

type LootSetGroupPrototype struct {
	LsgInfo     *worlddb.LootSetGroup       `json:"lsgInfo"`
	LsgiIndexes []*worlddb.LootSetGroupItem `json:"lsgiIndexes"`
	LootSetGroupItemPrototype
	LsgcIndexes []*worlddb.LootSetGroupCheque `json:"lsgcIndexes"`
	LootSetGroupChequePrototype
}

type LootSetGroupItemPrototype struct {
	LsgiInfo *worlddb.LootSetGroupItem `json:"lsgiInfo"`
}

type LootSetGroupChequePrototype struct {
	LsgcInfo *worlddb.LootSetGroupCheque `json:"lsgcInfo"`
}

type lootSetWebPrototype struct {
	LootSetPrototype
}

type lootSetGroupWebPrototype struct {
	LsgIndexes []*worlddb.LootSetGroup `json:"lsgIndexes"`
	LootSetGroupPrototype
}

type lootSetGroupItemWebPrototype struct {
	LsgiIndexes []*worlddb.LootSetGroupItem `json:"lsgiIndexes"`
	LootSetGroupItemPrototype
}

type lootSetGroupChequeWebPrototype struct {
	LsgcIndexes []*worlddb.LootSetGroupCheque `json:"lsgcIndexes"`
	LootSetGroupChequePrototype
}

func handleGetLootDialogArgs(w http.ResponseWriter, r *http.Request) {
	questRows, err := getAllQuest4DialogTable(worldDB)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	itemRows, err := getAllItem4DialogTable(worldDB)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	dialogArgs := map[string]interface{}{
		"questRows": questRows,
		"itemRows":  itemRows,
	}
	jsonData, err := json.Marshal(dialogArgs)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, jsonData)
}

func handleGetLootUIView(w http.ResponseWriter, r *http.Request) {
	uiViews := map[string]interface{}{
		"PlayerCareer": getViewPlayerCareer(),
		"PlayerGender": getViewPlayerGender(),
		"ChequeType":   getViewChequeType(),
	}
	jsonData, err := json.Marshal(uiViews)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, jsonData)
}

func handleGetLootTreeView(w http.ResponseWriter, r *http.Request) {
	handleGetEditorTreeView(
		w, r, worlddb.EditorTreeView_Type_Loot, getAllLootNames)
}

func handleSaveLootTreeView(w http.ResponseWriter, r *http.Request) {
	handleSaveEditorTreeView(w, r, worlddb.EditorTreeView_Type_Loot)
}

func handleGetLootInstance(w http.ResponseWriter, r *http.Request) {
	lsID, err := strconv.ParseUint(r.FormValue("LsID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsData, err := getLootSetInstanceJsonData(worldDB, uint32(lsID))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, lsData)
}

func handleNewLootInstance(w http.ResponseWriter, r *http.Request) {
	lsName := r.FormValue("LsName")
	if lsName == "" {
		http.Error(w, "empty loot set name.", http.StatusBadRequest)
		return
	}
	var lsID uint32
	err := fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		lsID, err = newLootSetInstance(tx, lsName)
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	lsData, err := getLootSetInstanceJsonData(worldDB, lsID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, lsData)
}

func handleCopyLootInstance(w http.ResponseWriter, r *http.Request) {
	lsID, err := strconv.ParseUint(r.FormValue("LsID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var ID uint32
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		ID, err = copyLootSetInstance(worldDB, tx, uint32(lsID))
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	lsData, err := getLootSetInstanceJsonData(worldDB, ID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJsonResponseData(w, lsData)
}

func handleDeleteLootInstance(w http.ResponseWriter, r *http.Request) {
	lsID, err := strconv.ParseUint(r.FormValue("LsID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) error {
		return deleteLootSetInstance(tx, uint32(lsID))
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeOKResponseData(w)
}

func handleSaveLootInstance(w http.ResponseWriter, r *http.Request) {
	lsData, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	var lsProto LootSetPrototype
	if err = json.Unmarshal(lsData, &lsProto); err != nil {
		http.Error(w, err.Error(), http.StatusNotAcceptable)
		return
	}
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) error {
		return saveLootSetInstance(tx, &lsProto)
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeOKResponseData(w)
}

func handleGetLootGroupInstance(w http.ResponseWriter, r *http.Request) {
	lsID, err := strconv.ParseUint(r.FormValue("LsID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgID, err := strconv.ParseUint(r.FormValue("LsgID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgData, err := getLootSetGroupInstanceJsonData(
		worldDB, uint32(lsID), uint32(lsgID))
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	writeJsonResponseData(w, lsgData)
}

func handleNewLootGroupInstance(w http.ResponseWriter, r *http.Request) {
	lsID, err := strconv.ParseUint(r.FormValue("LsID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var lsgID uint32
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		lsgID, err = newLootSetGroupInstance(tx, uint32(lsID))
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	lsgData, err := getLootSetGroupInstanceJsonData(
		worldDB, uint32(lsID), lsgID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	writeJsonResponseData(w, lsgData)
}

func handleCopyLootGroupInstance(w http.ResponseWriter, r *http.Request) {
	lsID, err := strconv.ParseUint(r.FormValue("LsID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgID, err := strconv.ParseUint(r.FormValue("LsgID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var ID uint32
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		ID, err = copyLootSetGroupInstance(worldDB, tx, uint32(lsgID))
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	lsgData, err := getLootSetGroupInstanceJsonData(
		worldDB, uint32(lsID), ID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	writeJsonResponseData(w, lsgData)
}

func handleDeleteLootGroupInstance(w http.ResponseWriter, r *http.Request) {
	lsgID, err := strconv.ParseUint(r.FormValue("LsgID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) error {
		return deleteLootSetGroupInstance(tx, uint32(lsgID))
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeOKResponseData(w)
}

func handleGetLootGroupItemInstance(w http.ResponseWriter, r *http.Request) {
	lsgID, err := strconv.ParseUint(r.FormValue("LsgID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgiID, err := strconv.ParseUint(r.FormValue("LsgiID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgiData, err := getLootSetGroupItemInstanceJsonData(
		worldDB, uint32(lsgID), uint32(lsgiID))
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	writeJsonResponseData(w, lsgiData)
}

func handleNewLootGroupItemInstance(w http.ResponseWriter, r *http.Request) {
	lsID, err := strconv.ParseUint(r.FormValue("LsID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgID, err := strconv.ParseUint(r.FormValue("LsgID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var lsgiID uint32
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		lsgiID, err = newLootSetGroupItemInstance(
			tx, uint32(lsID), uint32(lsgID))
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	lsgiData, err := getLootSetGroupItemInstanceJsonData(
		worldDB, uint32(lsgID), lsgiID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	writeJsonResponseData(w, lsgiData)
}

func handleCopyLootGroupItemInstance(w http.ResponseWriter, r *http.Request) {
	lsgID, err := strconv.ParseUint(r.FormValue("LsgID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgiID, err := strconv.ParseUint(r.FormValue("LsgiID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var ID uint32
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		ID, err = copyLootSetGroupItemInstance(
			worldDB, tx, uint32(lsgiID))
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	lsgiData, err := getLootSetGroupItemInstanceJsonData(
		worldDB, uint32(lsgID), ID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	writeJsonResponseData(w, lsgiData)
}

func handleDeleteLootGroupItemInstance(w http.ResponseWriter, r *http.Request) {
	lsgiID, err := strconv.ParseUint(r.FormValue("LsgiID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) error {
		return deleteLootSetGroupItemInstance(tx, uint32(lsgiID))
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeOKResponseData(w)
}

func handleGetLootGroupChequeInstance(w http.ResponseWriter, r *http.Request) {
	lsgID, err := strconv.ParseUint(r.FormValue("LsgID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgcID, err := strconv.ParseUint(r.FormValue("LsgcID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgcData, err := getLootSetGroupChequeInstanceJsonData(
		worldDB, uint32(lsgID), uint32(lsgcID))
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	writeJsonResponseData(w, lsgcData)
}

func handleNewLootGroupChequeInstance(w http.ResponseWriter, r *http.Request) {
	lsID, err := strconv.ParseUint(r.FormValue("LsID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgID, err := strconv.ParseUint(r.FormValue("LsgID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var lsgcID uint32
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		lsgcID, err = newLootSetGroupChequeInstance(
			tx, uint32(lsID), uint32(lsgID))
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	lsgcData, err := getLootSetGroupChequeInstanceJsonData(
		worldDB, uint32(lsgID), lsgcID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	writeJsonResponseData(w, lsgcData)
}

func handleCopyLootGroupChequeInstance(w http.ResponseWriter, r *http.Request) {
	lsgID, err := strconv.ParseUint(r.FormValue("LsgID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	lsgcID, err := strconv.ParseUint(r.FormValue("LsgcID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var ID uint32
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) (err error) {
		ID, err = copyLootSetGroupChequeInstance(
			worldDB, tx, uint32(lsgcID))
		return
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	lsgcData, err := getLootSetGroupChequeInstanceJsonData(
		worldDB, uint32(lsgID), ID)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	writeJsonResponseData(w, lsgcData)
}

func handleDeleteLootGroupChequeInstance(w http.ResponseWriter, r *http.Request) {
	LsgcID, err := strconv.ParseUint(r.FormValue("LsgcID"), 0, 32)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	err = fusion.RunDBTransaction(worldDB, func(tx *sql.Tx) error {
		return deleteLootSetGroupChequeInstance(tx, uint32(LsgcID))
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeOKResponseData(w)
}
